package primetest.impl.dao;

import java.io.IOException;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.sql.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import primetest.dto.DepartmentDto;
import primetest.impl.dao.DepartmentDao;
import primetest.impl.dao.Transaction;

//@Stateless
public class DepartmentDao implements Serializable {
	/**
	 *
	 */
	private static final long serialVersionUID = 6551770662358620809L;

	private final Logger logger = LoggerFactory.getLogger(this.getClass());


	private static List<DepartmentDto> allItems = null;
	private static HashMap<Integer, DepartmentDto> map = null;
	private static AtomicInteger count = null;

	@Inject
	public DepartmentDao(){
	}

	public List<DepartmentDto> getAllList(Transaction transaction) throws IOException {
		if (allItems != null) {
			return allItems;
		}
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;
		map = new HashMap<Integer, DepartmentDto>();
		int cnt = 0;
		try {

			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(GET_ALL);
			resultSet = prepareStatement.executeQuery();

			while (resultSet.next()) {
				DepartmentDto departmentDto = makeDepartmentDto(transaction, resultSet);
				map.put(departmentDto.getSeq(), departmentDto);
				if (departmentDto.getSeq() > cnt) {
					cnt = departmentDto.getSeq();
				}
			}
			allItems = new ArrayList<DepartmentDto>(map.values());
			count = new AtomicInteger(++cnt);
			return allItems;
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}

	private DepartmentDto makeDepartmentDto(Transaction transaction, ResultSet resultSet) throws SQLException, IOException {
		DepartmentDto departmentDto = new DepartmentDto(resultSet.getInt(1), resultSet.getString(2),
				resultSet.getString(3), resultSet.getDate(4));
		return departmentDto;
	}



	public DepartmentDto findDepartment(Transaction transaction, int seq) throws IOException {
		if(allItems == null){
			getAllList(transaction);
		}
		return map.get(seq);
	}

	public void addDepartment(Transaction transaction, DepartmentDto departmentDto) throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;

		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(INSERT_ONE);
			departmentDto.setSeq(count.getAndIncrement());
			prepareStatement.setInt(1, departmentDto.getSeq());
			prepareStatement.setString(2, departmentDto.getName());
			prepareStatement.setString(3, departmentDto.getDescription());
			prepareStatement.setDate(4, new Date(departmentDto.getBuildDate().getTime()));
			prepareStatement.executeUpdate();
			map.put(departmentDto.getSeq(), departmentDto);
			allItems.add(departmentDto);
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}

	public void updateDepartment(Transaction transaction, DepartmentDto departmentDto) throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;

		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(UPDATE_ONE);
			prepareStatement.setInt(4, departmentDto.getSeq());
			prepareStatement.setString(1, departmentDto.getName());
			prepareStatement.setString(2, departmentDto.getDescription());
			prepareStatement.setDate(3, new Date(departmentDto.getBuildDate().getTime()));
			prepareStatement.executeUpdate();
			map.put(departmentDto.getSeq(), departmentDto);
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}

	}

	public void deleteDepartment(Transaction transaction, int departmentSeq) throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;
		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(DELETE_ONE);
			prepareStatement.setInt(1, departmentSeq);
			prepareStatement.executeUpdate();
			allItems.remove(map.remove(departmentSeq));
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}

	}

	private static final String GET_ALL = "select seq, name, description, build_date from s_department order by seq";
	private static final String INSERT_ONE = "insert into s_department(seq, name, description, build_date) values (?, ?, ?, ?)";
	private static final String UPDATE_ONE = "update s_department set name = ?, description = ?, build_date = ? where seq = ? ";
	private static final String DELETE_ONE = "delete from s_department where seq = ?";
}
